package com.clp.protocol.iec104;

import com.clp.protocol.core.pdu.PduRecvCallback;
import com.clp.protocol.core.pdu.nbytepdu.NBytePduClip;
import com.clp.protocol.iec104.apdu.asdu.IAsdu;
import com.clp.protocol.iec104.client.Iec104MasterManager;
import com.clp.protocol.iec104.client.Master;
import com.clp.protocol.iec104.client.MasterIAsduSender;
import com.clp.protocol.iec104.client.async.MasterFuture;
import com.clp.protocol.iec104.client.async.MasterFutureListener;
import com.clp.protocol.iec104.client.async.sendapdu.SendTcExecuteRes;
import com.clp.protocol.iec104.client.async.sendapdu.SendTcSelectRes;
import com.clp.protocol.iec104.client.config.MasterConfig;
import com.clp.protocol.iec104.client.config.MasterControlConfig;
import com.clp.protocol.iec104.client.config.MasterDataConfig;
import com.clp.protocol.iec104.client.pipeline.state.control.MControlInfo;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import java.awt.*;
import java.util.function.BiConsumer;

/**
 * IEC104主站功能说明：
 *  1、基于netty nio多路复用以及扩展的Promise模式异步编程；
 *  2、较为完整的启动流程：连接-》启动传输-》定时总召唤、电度量召唤；
 *  3、较为完善的异常处理机制：断线自动重连；T1T2T3超时处理；kw流量控制；等等
 *  4、使用简单：仅需一套简单的配置，即可实现各类测点数据的采集以及遥控、遥调命令下发。
 */
@Slf4j
public class TestClient {
    private static JFrame createJFrame() {
        JFrame jFrame = new JFrame();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        jFrame.setSize(screenSize);
        return jFrame;
    }

    public static void main(String[] args) throws Throwable {
        // 1、获取主站管理器
        Iec104MasterManager masterManager = Iec104MasterManager.get();
        // MasterStateManager中实现了一个简单的监视面板，可以用来显示当前的连接情况
        JFrame jFrame = createJFrame();
        jFrame.add(masterManager.getMonitorPanel());
        jFrame.setVisible(true);

        // 2、新建连接，返回的future类似netty的ChannelFuture，只不过这个是关联的主站Master
        MasterFuture<Void> masterConnFuture = masterManager.connect(
                MasterConfig.configurer()
                        .remote("127.0.0.1", 2404) // 连接的子站ip
                        .local(1) // 公共地址
                        .controlConfig(MasterControlConfig.configurer() // 控制配置
                                .maxReconnectCount(-1) // 最大重连次数，-1代表无限重连
                                .autoStartDtV(true) // 是否自动启动传输激活
                                .t0t1t2t3(6, 3, 2, 4) // t0, t1, t2 ,t3 超时时间，单位为秒
                                .kw(12, 8) // 发送窗口和接收窗口的大小，要求k大于w
                                .apduToStringFormat(NBytePduClip.ToStringFormat.DEFAULT_FORMAT) // APDU的打印格式，支持详细信息、十六进制、二进制
                                .configOk()
                        )
                        .dataConfig(MasterDataConfig.configurer() // 数据配置
                                .totalCall100PeriodSeconds(60) // 总召唤周期，单位为秒
                                .totalCall101PeriodSeconds(60) // 电度量召唤周期，单位为秒
                                .configOk()
                        )
                        .configOk()
        );

        // 等待连接结果
        // 这里既可以通过添加监听器实现异步，也可以调用sync()方法同步等待连接结果
        masterConnFuture.addListener(new MasterFutureListener<Void>() {
            @Override
            public void operationComplete(MasterFuture<Void> future) {
                if (future.isSuccess()) {
                    log.info("连接成功！");
                } else {
                    log.info("连接失败！");
                }
            }
        }).sync();

        // 如果连接成功，该master将加入至masterManager。可以从主站管理器或者MasterFuture中获取指定主站
        Master master1 = Iec104MasterManager.get().getMaster("127.0.0.1", 2404); // 如果连接失败，master1为null
        if (master1 == null) return;
        Master master2 = masterConnFuture.master();
        log.info("master1={}, master2={}, master1{}master2", master1, master2, master1 == master2);

        // 动态添加或移除回调处理函数
        PduRecvCallback<IAsdu> callback = frame -> {
            log.info("接收到帧：{}", frame);
            return false; // 每次接收到apdu都会执行
        };
        master2.getIAsduRecver().addRecvCallback(callback);
        // master2.getIAsduRecver().removeRecvCallback(callback);

        // 主站Asdu发送器提供了各种发送数据的API
//        MasterIAsduSender iAsduSender = master2.getIAsduSender();
//        iAsduSender.sendTotalCall100();
//        iAsduSender.sendTotalCall101();

        // 查看master状态
//        MControlInfo controlInfo = master2.controlInfo();
//        new Thread(() -> {
//            int count = 0;
//            while(++count < 100) {
//                try {
//                    Thread.sleep(1000 * 2);
//
//                    log.info("isConnected: " + master2.isConnected());
//                    log.info("isDoingTotalCall100: " + controlInfo.isDoingTotalCall100());
//                    log.info("isStartedDt: " + controlInfo.isStartedDt());
//                    log.info("isInitCompleted: " + controlInfo.isInitCompleted());
//                    log.info("");
//
//                    log.info("isConnected: " + master1.isConnected());
//                    log.info("isDoingTotalCall100: " + controlInfo.isDoingTotalCall100());
//                    log.info("isStartedDt: " + controlInfo.isStartedDt());
//                    log.info("isInitCompleted: " + controlInfo.isInitCompleted());
//                    log.info("");
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        });
//
//        Thread.sleep(1000 * 1);

        // 执行遥控命令，遥调同理
//        if (master2.controlInfo().isInitCompleted()) {
//            master2.getIAsduSender().sendOnePointTcSelect(24578, true).addListener(new MasterFutureListener<SendTcSelectRes>() {
//                @Override
//                public void operationComplete(MasterFuture<SendTcSelectRes> future) {
//                    if (future.isSuccess()) {
//                        log.info("遥控选择成功！");
//                        future.master().getIAsduSender().sendOnePointTcExecute(24578, true).addListener(new MasterFutureListener<SendTcExecuteRes>() {
//                            @Override
//                            public void operationComplete(MasterFuture<SendTcExecuteRes> future) {
//                                if (future.isSuccess()) {
//                                    log.info("遥控执行成功！");
//                                } else {
//                                    log.warn("遥控执行失败！");
//                                }
//                            }
//                        });
//                    } else {
//                        log.warn("遥控选择失败！");
//                    }
//                }
//            });
//        }

        // 尝试运行1分钟
//        Thread.sleep(1000 * 60);
//        log.info("<<<<<<<<<<< 即将断开...");
//        masterManager.disconnect(master1).sync();
//
//        // 关闭所有连接（如果有的话）
//        masterManager.disconnectAll().whenComplete(new BiConsumer<Boolean, Throwable>() {
//            @Override
//            public void accept(Boolean isSuccess, Throwable throwable) {
//                if (isSuccess) {
//                    log.info("断开成功！");
//                } else {
//                    log.info("断开失败！");
//                }
//            }
//        });
//        // 关闭主站管理器，即使不关闭，程序退出也会自动关闭
//        masterManager.close();
    }
}
